﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;

namespace Twitter
{
	/// <summary>
	/// Reads the payload from <see cref="XmlReader"/>.
	/// </summary>
	public static class PayloadReader
	{
		static XmlReaderSettings readerSettings;

		static PayloadReader()
		{
			readerSettings = new XmlReaderSettings();
			readerSettings.CheckCharacters = true;
			readerSettings.CloseInput = true;
			readerSettings.IgnoreComments = true;
			readerSettings.IgnoreProcessingInstructions = true;
			readerSettings.IgnoreWhitespace = true;
		}

		/// <summary>
		/// Reads messages.
		/// </summary>
		public static IEnumerable<Message> ReadMessages(XmlReader payload)
		{
			Guard.ArgumentNotNull(payload, "payload");

			XmlReader reader = XmlReader.Create(payload, readerSettings);

			if (reader.ReadToDescendant("direct_message"))
			{
				do
				{
					if (reader.ReadToDescendant("id"))
					{
						Message message = new Message
						{
							Id = reader.ReadElementContentAsString(),
							Text = reader.ReadToFollowing("text") ? reader.ReadElementContentAsString() : "",
							Created = reader.ReadToFollowing("created_at") ?
								Timestamp.Parse(reader.ReadElementContentAsString()) :
								(DateTime?)null,
							Sender = reader.ReadToFollowing("sender") ?
								ReadUser(reader.ReadSubtree()) : null,
							Recipient = reader.ReadToFollowing("recipient") ?
								ReadUser(reader.ReadSubtree()) : null
						};

						Tracer.TraceEvent(typeof(PayloadReader), TraceEventType.Verbose, 0,
							"Read message: Id={0}, Text={1}, Sender={2}, Recipient={3}",
							message.Id, message.Text,
							message.Sender.ScreenName, message.Recipient.ScreenName);

						yield return message;
					}
				} while (reader.ReadToFollowing("direct_message"));
			}
		}

		/// <summary>
		/// Read statuses.
		/// </summary>
		public static IEnumerable<Status> ReadStatuses(XmlReader payload)
		{
			Guard.ArgumentNotNull(payload, "payload");

			using (XmlReader reader = XmlReader.Create(payload, readerSettings))
			{
				if (reader.ReadToDescendant("statuses") &&
					reader.ReadToDescendant("status"))
				{
					do
					{
						if (reader.ReadToDescendant("created_at"))
						{
							Status status = new Status()
							{
								Created = Timestamp.Parse(reader.ReadElementContentAsString()),
								Id = reader.ReadElementContentAsString(),
								Text = reader.ReadElementContentAsString(),
								Source = reader.ReadElementContentAsString(),
								Truncated = reader.ReadElementContentAsBoolean(), 
								User = ReadUser(reader.ReadSubtree())
							};

							Tracer.TraceEvent(typeof(PayloadReader), TraceEventType.Verbose, 0,
								"Read status: Id={0}, Text={1}, User={2}",
								status.Id, status.Text, status.User.ScreenName);

							yield return status;
						}
					} while (reader.ReadToFollowing("status"));
				}
			}
		}

		public static IEnumerable<string> ReadUserScreenNames(XmlReader payload)
		{
			Guard.ArgumentNotNull(payload, "payload");

			using (XmlReader reader = XmlReader.Create(payload, readerSettings))
			{
				object screenName = reader.NameTable.Add("screen_name");

				// Path: /users/user/screen_name/
				// TODO: return full User instances?
				while (reader.Read())
				{
					if (reader.NodeType == XmlNodeType.Element &&
						screenName == (object)reader.LocalName)
					{
						string user = reader.ReadElementContentAsString();

						Tracer.TraceEvent(typeof(PayloadReader), TraceEventType.Verbose, 0,
							"Read user {0}", user);

						yield return user;
					}
				}
			}
		}

		public static User ReadProfile(XmlReader payload)
		{
			Guard.ArgumentNotNull(payload, "payload");

			using (XmlReader reader = XmlReader.Create(payload, readerSettings))
			{
				if(reader.ReadToDescendant("user"))
					return ReadUser(reader);
			}

			return null;
		}

		private static User ReadUser(XmlReader reader)
		{
			/*
	<user>
	  <id>10693622</id>
	  <name>Daniel Cazzulino</name>
	  <screen_name>kzu</screen_name>
	  <location>Buenos Aires</location>
	  <description></description>
	  <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/38459092/kzubuddy_normal.png</profile_image_url>
	  <url>http://clariusconsulting.net/kzu</url>
	  <protected>false</protected>
	</user>
		*/
			return new User
			{
				Id = reader.ReadToDescendant("id") ?
					reader.ReadElementContentAsString() :
					null,
				Name = reader.ReadElementContentAsString(),
				ScreenName = reader.ReadElementContentAsString(),
				Location = reader.ReadElementContentAsString(),
				Description = reader.ReadElementContentAsString(),
				ProfileImageUrl = reader.ReadElementContentAsString(),
				Url = reader.ReadElementContentAsString(),
				Protected = reader.ReadElementContentAsBoolean()
			};
		}
	}
}
